import type { SerialTaskExecuteContext } from '../handler'

import { SerialHandler } from '../handler'

class RecordActuator extends SerialHandler<Float32Array[] | null, Float32Array> {
  private audioContext: AudioContext | null = null
  private processor: ScriptProcessorNode | null = null
  private source: MediaStreamAudioSourceNode | null = null

  protected onActive(): void {
    this.audioContext = new AudioContext()
    this.audioContext.resume()
  }

  public execute(context: SerialTaskExecuteContext<Float32Array[] | null, Float32Array>): void {
    if (context.isLastExecute) {
      this.taskCompletedCallback()
      return
    }

    (context.taskItem.original || []).forEach((item) => {
      this.forwardToHandler(item)
    })

    navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then((stream) => {
      this.processor = this.audioContext!.createScriptProcessor(0, 1, 1)

      this.processor.onaudioprocess = (event) => {
        if (this.isHandleDataAcceptedComplete) {
          return this.taskCompletedCallback()
        }

        const original: Float32Array = event.inputBuffer.getChannelData(0)

        this.forwardToHandler(original)
      }
      this.source = this.audioContext!.createMediaStreamSource(stream)
      this.source.connect(this.processor)
      this.processor.connect(this.audioContext!.destination)
    })
  }

  protected onCompleted(): void {
    if (this.source) {
      this.source.disconnect()
      this.source = null
    }
    if (this.processor) {
      this.processor.disconnect()
      this.processor = null
    }
    if (this.audioContext) {
      this.audioContext.suspend()
      this.audioContext = null
    }
  }

  protected onFinish(): void {
    if (this.source) {
      this.source.disconnect()
      this.source = null
    }
    if (this.processor) {
      this.processor.disconnect()
      this.processor = null
    }
    if (this.audioContext) {
      this.audioContext.suspend()
      this.audioContext = null
    }

    this.executeController?.$bus.emit('_recordActuatorFinish')
  }
}

export default RecordActuator
